﻿using System;
using System.Collections.Generic;
using System.Linq;
using MiniShellFramework;
using MiniShellFramework.ComTypes;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Diagnostics.Contracts;
using System.Diagnostics;
using System.Reflection;
using System.IO;

namespace PerformanceDude.MSBuildShellExtension
{
    [ComVisible(true)]                              // Make this .NET class a COM object (ComVisible is false on assembly level).
    [Guid("B6D077CB-F823-4F5B-9E44-F3719175B04C")]  // Explicitly assign a GUID: easier to reference and to debug.
    [ClassInterface(ClassInterfaceType.None)]       // Only the functions from the COM interfaces should be accessible.
    public sealed class ContextMenu : ContextMenuBase, IDisposable
    {
        private readonly Bitmap bitmapMenuIcon;
        private readonly Bitmap bitmapHelpIcon;
        private readonly Bitmap bitmapAboutIcon;
        private static Menu contextMenu;

        public ContextMenu()
        {
			bitmapMenuIcon = new Bitmap(typeof(ContextMenu), "menuicon.bmp");
			bitmapMenuIcon.MakeTransparent(Color.White);

            Icon helpIcon = new Icon(new Icon(typeof(ContextMenu), "Help.ico"), new Size(16, 16));
            bitmapHelpIcon = helpIcon.ToBitmap();
            bitmapHelpIcon.MakeTransparent(Color.White);

            Icon aboutIcon = new Icon(new Icon(typeof(ContextMenu), "About.ico"), new Size(16, 16));
            bitmapAboutIcon = aboutIcon.ToBitmap();
            bitmapAboutIcon.MakeTransparent(Color.White);

			foreach (string fileExtension in MSBuildRootKey.FileExtensions)
			{
				RegisterExtension(fileExtension);
			}
        }

        [ComRegisterFunction]
        public static void ComRegisterFunction(Type type)
        {
            Contract.Requires(type != null);

			MSBuildRootKey.Register();

			bool fileAssociationExists = false;

			foreach (string fileExtension in MSBuildRootKey.FileExtensions)
			{
				string existingProgId;
				if (RootKey.TryGetProgIdForFileExension(fileExtension, out existingProgId))
				{
					fileAssociationExists = true;
					ComRegister(type, MSBuildRootKey.Description, existingProgId);
				}
			}

			if (!fileAssociationExists)
			{
				ComRegister(type, MSBuildRootKey.Description, MSBuildRootKey.ProgId);
			}
        }

        [ComUnregisterFunction]
        public static void ComUnregisterFunction(Type type)
        {
            Contract.Requires(type != null);

			//do not unregister file extensions or progid because it may break existing file associations
			//MSBuildRootKey.Unregister();
			//ComUnregister(type, MSBuildRootKey.Description, MSBuildRootKey.ProgId);
        }

        protected override void QueryContextMenuCore(Menu menu, IList<string> filenames)
        {
            if (filenames.Count != 1 || ContainsUnknownExtension(filenames))
                return;
            
            //TODO: Low: support multiple file selections

            contextMenu = menu.AddSubMenu("MSBuild", new BitmapCustomMenuHandler("MSBuild", bitmapMenuIcon));

            MSBuildFile msBuildFile = new MSBuildFile(filenames[0]);

            foreach (MSBuildFileTarget target in msBuildFile.Targets)
            {
                string fullTargetName = target.TargetName;
                if (!string.IsNullOrEmpty(target.ConfigurationName))
                {
                    fullTargetName += " " + target.ConfigurationName + "|" + target.PlatformName;
                }
                contextMenu.AddItem(fullTargetName, "Execute Target \"" + fullTargetName + "\" on the file with MSBuild", OnTarget);
            }

            contextMenu.AddItem(new BitmapCustomMenuHandler("&Help", bitmapHelpIcon), "View the help documentation for MSBuild Shell Extension", OnHelp);
            contextMenu.AddItem(new BitmapCustomMenuHandler("&About MSBuild Shell Extension", bitmapAboutIcon), "Show information about MSBuild Shell Extension", OnAboutMSBuild);
            
        }

        private static void OnTarget(ref InvokeCommandInfo invokeCommandInfo, IList<string> fileNames)
        {
            Contract.Requires(fileNames != null);
            Contract.Requires(fileNames.Count == 1);

            MSBuildFile msBuildFile = new MSBuildFile(fileNames[0]);

            int itemIndex = Int32.Parse(invokeCommandInfo.lpVerb.ToString());

            MSBuildFileTarget target = msBuildFile.Targets.ElementAt(itemIndex - 1);

            MSBuildRunner msBuildRunner = new MSBuildRunner();
            msBuildRunner.Run(fileNames[0], msBuildFile.VersionString, target.TargetName, target.ConfigurationName, target.PlatformName, true);
        }

        private static void OnAboutMSBuild(ref InvokeCommandInfo invokeCommandInfo, IList<string> fileNames)
        {
            AboutDialog aboutDialog = new AboutDialog();
            aboutDialog.ShowDialog();
        }

        private static void OnHelp(ref InvokeCommandInfo invokeCommandInfo, IList<string> fileNames)
        {
			string dllFilePath = Assembly.GetExecutingAssembly().Location;
			string appPath = System.IO.Path.GetDirectoryName(dllFilePath);
			Process.Start(Path.Combine(appPath, "MSBuildShellEx.chm"));
        }

        public void Dispose()
        {
            Debug.WriteLine("{0}.Dispose", this);
            bitmapMenuIcon.Dispose();
        }
    }
}
